import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
 
/** A "pretty-formatter" for HTML files writes a file called "<file to read>F.html".
 * Usage: java HTMLFormatter "<indentation>" <list of files to read> 
 * @author Gregory L Burgess
 * @date March 07, 2012
 */

public class HTMLFormatter {
  
  /** Regex expression for tags that don't have a matched closing tag. 
      This includes tags that are self-terminating.**/ 
  public static String regex = "^<\\s*!.*|^<\\s*link.*|^<\\s*/?script.*|^<\\s*meta.*|^<\\s*img.*|^<\\s*/?br.*|^<\\s*input.*|^<\\s*hr.*";
  
  
  public static void main(String[] args) {
    if (args.length < 2) {
      System.err.println("Usage: java HTMLFormatter \"<indentation>\" <list of files to read> .");
      System.exit(0);
    }
    for (int i = 1; i < args.length; i++) {
      filePrep(args[i],args[0]);
    }
  }
  
  /**
   * Handles the file IO for the file to be formatted.
   * @param file The filename of the file to be formatted.
   * @param indent The indentation to use.
   */
  public static void filePrep (String file, String indent) {
      String lineIn = "";
      String inFile = file;
      String lines = "";
      Object[] outLines;
      //setup
      try { 
        FileInputStream fstream = new FileInputStream(inFile); 
        DataInputStream in = new DataInputStream(fstream);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        
        //read in file
        while ((lineIn = br.readLine()) != null) { 
          lines += lineIn;
        } 
        in.close();
        
        //heavy lifting
        outLines= format(lines, indent); 
        
        // Create file 
        //get file name 
        String outFile = inFile.split("\\.")[0]; 
        
        FileWriter ostream = new FileWriter(outFile + "F.html");
        BufferedWriter out = new BufferedWriter(ostream); 
        //write 
        for (Object str : outLines) {
          out.write((String)str + "\n");
        }
        
        //Close the output stream
        out.close();
      }
      catch (Exception e) { 
        System.err.println("Error: " + e.getMessage());
        e.printStackTrace();
      } 
  
  }
  
  
  /**
   * Formats an HTML file concatenated to a single string.
   * @param in The HTML file as a single string.
   * @param spacer The indentation to use for the formatting.
   * @return An array of Objects (Strings).
   */
  private static Object[] format(String in, String spacer) { 
    String tabs = "";
    int type,lastType=2;
    String templine = "";
    // Using "!>>" as a special symbol as it's invalid in HTML.
    in = in.replaceAll(">", ">!>>"); 
    in = in.replaceAll("<", "!>><");
    in = in.replaceAll("\n", "");  
    ArrayList<String> list = new ArrayList<String>(Arrays.asList(in.split("!>>")));   
     
    
    for (int i = 0;i < list.size(); i ++) {   
      templine = list.get(i).trim(); 
      //Remove the line in question, as it may 
      //be split into multiple lines later on...
      list.remove(i);
      if (!templine.matches("^\\s*") && templine !=null && templine.length()>0) {
        //identify the line type
        type = getTagType(templine); 
        
        // Logic to format lines
        if (type == -1 && lastType != 1) {
          tabs = tabs.substring(spacer.length());
        } 
        else if (lastType == 1 && type != -1) {
          tabs += spacer;
        } 
        if (lastType == 2) {
          tabs = "";
        } 
        //Re-insert lines into file.
        list.add(i,tabs+templine); 
        lastType = type;  
      } 
      else {
        i--;
      }
    } 
    return list.toArray(); 
  }
  
  
  /** Determines the type of the first tag (if any) in the string, 
   *  returning: 
   *  1 if start tag, 
   *  -1 if end tag, 
   *  0 if content.
   *  @param inputString the string containing the tag to identify.
   *  @return the type of the first tag (if any) in the string.
   **/
  private static int getTagType(String inputString) {
    if (inputString.length()<=1) {
      return 0;
    }
    char firstChar=inputString.charAt(0);
    char secondChar = inputString.charAt(1);
    
    if (firstChar != '<' || inputString.matches(regex)) { 
      return 0;
    }
    else {
      if(secondChar == '/') {  
        return -1;
      }
      else { 
        return 1;   
      }
    } 
  }
   
}